今天我們來思考在外送平台常見的
拖曳地圖抓地址的功能怎麼做?
當以上問題解完其實就能寫出來了
抓目前題圖的中心點 經緯度
map.getCenter();
//{
//     "lat": 24.153940200805668,
//     "lng": 120.6743698120117
// }
透過免費的 API 將經緯度轉地址名稱
可以到以下官網試試看:
https://nominatim.openstreetmap.org/ui/reverse.html
我們可以用"address"或是"display_name"的資訊
要特別注意"display_name"對我們來說是反向的
// "display_name": "210號, 五權一街, 大忠里, 西區, 田心, 臺中市, 403, 臺灣",
// "address": {
//     "house_number": "210號",
//     "road": "五權一街",
//     "neighbourhood": "大忠里",
//     "suburb": "西區",
//     "village": "田心",
//     "city": "臺中市",
//     "ISO3166-2-lvl4": "TW-TXG",
//     "postcode": "403",
//     "country": "臺灣",
//     "country_code": "tw"
// },
//地圖開始移動:隱藏 tooltip
map.on("movestart", () => {
  this.centerMarker.closeTooltip();
});
//地圖移動中:更改 marker 位置
map.on("move", () => {
  const center = map.getCenter();
  this.centerMarker.setLatLng(center);
});
//地圖移動完成:更改文字後,開啟 tooltip
map.on("moveend", () => {
  updateMarker();
  this.centerMarker.openTooltip();
});
// 先取得 marker 的經緯度再轉換成地址
const updateMarker = () => {
  const latlng = this.centerMarker.getLatLng();
  updateAddress(latlng, this.centerMarker);
};
//call api 轉換後將 marker 文字更改
function updateAddress({ lat, lng }, centerMarker) {
  centerMarker.setTooltipContent("Loading...");
  const url = `https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lng}`;
  fetch(url)
    .then((response) => response.json())
    .then((data) => {
      const address = data.display_name || "No address found";
      const reverseAddress = address.split(",").reverse().join("");
      centerMarker.setTooltipContent(reverseAddress);
    })
    .catch(() => {
      centerMarker.setTooltipContent("Unable to load address");
    });
}
其實最早我完成的是這個
demo2
手動移動 marker 來更新地圖
但使用後發現不好用XD
果然外送平台的做法UX還是比較讚!
移動地圖抓中心點非常直覺~
有興趣可以實際操作看看最後的成果:
demo1
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>DAY-4 移動地圖抓中心點地址 Example</title>
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css"
    />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js"></script>
    <style>
      body {
        background-color: black;
        padding: 0;
        margin: 0;
      }
      .wrapper {
        width: 99dvw;
        height: 99dvh;
        display: flex;
        justify-content: center;
        align-items: center;
      }
      #map {
        height: 100%;
        width: 100%;
      }
    </style>
  </head>
  <body>
    <div class="wrapper">
      <div id="map"></div>
    </div>
    <script>
      const myMap = {
        map: null,
        centerMarker: null,
        init() {
          this.map = L.map("map").setView(
            [24.153940200805668, 120.6743698120117],
            14
          );
          //圖層
          L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
            attribution: "© OpenStreetMap contributors",
          }).addTo(this.map);
        },
        generateMarker() {
          const map = this.map;
          // 在地圖中心放一個可移動的 marker
          this.centerMarker = L.marker(map.getCenter(), {
            draggable: true,
          }).addTo(map);
          // 初始化 Tooltip
          this.centerMarker
            .bindTooltip("Loading address...", {
              permanent: true,
              direction: "top",
            })
            .openTooltip();
        },
        main() {
          // 產生marker
          this.generateMarker();
          // 更新 marker 的位置和地址
          const updateMarker = () => {
            const latlng = this.centerMarker.getLatLng();
            updateAddress(latlng, this.centerMarker);
          };
          // 初次載入地圖時更新一次 marker 位置和地址
          updateMarker();
          const map = this.map;
          // 當地圖拖動結束時更新 marker 位置和地址
          map.on("movestart", () => {
            this.centerMarker.closeTooltip();
          });
          map.on("move", () => {
            const center = map.getCenter();
            this.centerMarker.setLatLng(center);
          });
          map.on("moveend", () => {
            updateMarker();
            this.centerMarker.openTooltip();
          });
        },
      };
      myMap.init();
      myMap.main();
      // call api 更新地點的地址
      function updateAddress({ lat, lng }, centerMarker) {
        centerMarker.setTooltipContent("Loading...");
        const url = `https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lng}`;
        fetch(url)
          .then((response) => response.json())
          .then((data) => {
            const address = data.display_name || "No address found";
            const reverseAddress = address.split(",").reverse().join("");
            centerMarker.setTooltipContent(reverseAddress);
          })
          .catch(() => {
            centerMarker.setTooltipContent("Unable to load address");
          });
      }
    </script>
  </body>
</html>